#include "GameScene.h"
#include "MenuScene.h"
#include "Scores.h"
#include "SimpleAudioEngine.h"

Game::Game() :
		ghostTag(0), projectileTag(1) {

}

Game::~Game() {
	if (pScores) {
		delete this->pScores;
	}
	if (this->pGhosts) {
		pGhosts->release();
		pGhosts = NULL;
	}

	if (this->pProjectiles) {
		pProjectiles->release();
		pProjectiles = NULL;
	}
}

CCScene* Game::scene() {
	// 'scene' is an autorelease object
	CCScene *scene = CCScene::create();

	// 'layer' is an autorelease object
	Game *layer = Game::create();

	// add layer as a child to scene
	scene->addChild(layer);

	// return the scene
	return scene;
}

bool Game::init() {
	if (!CCLayer::init()) {
		return false;
	}

	// Menu
	CCMenuItemImage *pBackItem = CCMenuItemImage::create("back.png", "back.png",
			this, menu_selector(Game::menuBackCallback));
	pBackItem->setPosition(ccp(50, 30));
	CCMenu* pMenu = CCMenu::create(pBackItem, NULL);
	pMenu->setPosition(CCPointZero);
	this->addChild(pMenu, 1);

	CCSize visableSize = CCDirector::sharedDirector()->getVisibleSize();
	this->pScores = new Scores(this);
	// Background
	CCSprite *pBackgroundSprite = CCSprite::create("bg.png");
	pBackgroundSprite->setPosition(
			ccp(visableSize.width / 2, visableSize.height / 2));
	this->addChild(pBackgroundSprite, 0);

	// Gun
	this->pGun = CCSprite::create("gun.png");
	this->gunPosition = ccp(visableSize.width / 2, 50);
	this->pGun->setPosition(gunPosition);
	this->addChild(this->pGun, 2);
	this->setTouchEnabled(true);

	this->visibleSize = CCDirector::sharedDirector()->getVisibleSize();
	this->left = 0 - 50;
	this->right = visibleSize.width + 50;
	this->maxV = 800 / 4;
	this->minV = 800 / 20;
	this->minY = 160;
	this->maxY = visibleSize.height - 100;

	this->schedule(schedule_selector(Game::gameLogic), 1.0);

	this->pGhosts = new CCArray();
	this->pProjectiles = new CCArray();
	this->schedule(schedule_selector(Game::update));
	return true;
}

void Game::update(float dt) {
	CCArray *projectilesToDelete = new CCArray;
	CCObject* it = NULL;
	CCObject* jt = NULL;

	CCARRAY_FOREACH(pProjectiles, it) {
		CCSprite *projectile = dynamic_cast<CCSprite*>(it);
		CCRect projectileRect =
				CCRectMake(
						projectile->getPosition().x - (projectile->getContentSize().width/2),
						projectile->getPosition().y - (projectile->getContentSize().height/2),
						projectile->getContentSize().width,
						projectile->getContentSize().height);

		CCArray* targetsToDelete = new CCArray;

		CCARRAY_FOREACH(pGhosts, jt) {
			CCSprite *target = dynamic_cast<CCSprite*>(jt);
			CCRect targetRect =
					CCRectMake(
							target->getPosition().x - (target->getContentSize().width/2),
							target->getPosition().y - (target->getContentSize().height/2),
							target->getContentSize().width,
							target->getContentSize().height);

			if (projectileRect.intersectsRect(targetRect)) {
				targetsToDelete->addObject(target);
			}

		}

		CCARRAY_FOREACH(targetsToDelete, jt) {
			CCSprite *target = dynamic_cast<CCSprite*>(jt);
			CCSprite *bomb = CCSprite::create("bomb.png");
			bomb->setPosition(target->getPosition());
			this->addChild(bomb, 10);
			CocosDenshion::SimpleAudioEngine::sharedEngine()->playEffect("bomb.wav");
			bomb->runAction(
					CCSequence::create(CCFadeOut::create(1.0f),
									CCCallFuncN::create(this,
											callfuncN_selector(Game::actionBombEnd)),
							NULL));
			pGhosts->removeObject(target, true);
			this->removeChild(target, true);
		}

		if (targetsToDelete->count() > 0) {
			projectilesToDelete->addObject(projectile);
		}
		targetsToDelete->release();
	}

	CCARRAY_FOREACH(projectilesToDelete, it) {
		CCSprite* projectile = dynamic_cast<CCSprite*>(it);
		pProjectiles->removeObject(projectile, true);
		this->removeChild(projectile, true);
	}
	projectilesToDelete->release();
}

void Game::gameLogic(float dt) {
	this->addGhost();
}

void Game::addGhost() {
	CCSprite *ghost = CCSprite::create("ghost01.png");
	ghost->setTag(ghostTag);
	this->pGhosts->addObject(ghost);
	float y = (CCRANDOM_0_1() * (maxY - minY)) + minY;
	float v = (CCRANDOM_0_1() * (maxV - minV)) + minV;
	CCFiniteTimeAction* actionMove = NULL;
	if ((CCRANDOM_0_1() * 10) <= 4) {
		ghost->setPosition(ccp((float)left, (float)y));
		actionMove = CCMoveTo::create((float) visibleSize.width / v,
				ccp(right, y));
	} else {
		ghost->setPosition(ccp((float)right, (float)y));
		actionMove = CCMoveTo::create((float) visibleSize.width / v,
				ccp(left, y));
	}

	this->addChild(ghost, 1);
	CCFiniteTimeAction* actionMoveDone = CCCallFuncN::create(this,
			callfuncN_selector(Game::ghostMoveFinished));
	ghost->runAction(CCSequence::create(actionMove, actionMoveDone, NULL));
}

void Game::ghostMoveFinished(CCNode *sender) {
	CCSprite *sprite = (CCSprite *) sender;
	this->removeChild(sprite, true);
	pGhosts->removeObject(sprite, true);
}

void Game::actionBombEnd(CCNode *sender) {
	CCSprite *sprite = (CCSprite *) sender;
	this->removeChild(sprite, true);
}

void Game::ccTouchesBegan(CCSet *pTouches, CCEvent * pEvent) {
	if (!this->running) {
		CCTouch* touch = (CCTouch*) (pTouches->anyObject());
		CCPoint location = touch->getLocation();
		if (location.y < 100)
			return;
		CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();
		this->offX = location.x - gunPosition.x;
		this->offY = location.y - gunPosition.y;

		this->angleRadians = atanf((float) offX / (float) offY);
		float angleDegrees = CC_RADIANS_TO_DEGREES(angleRadians);
		float rotateVelocity = 180 / 1;
		float rotateDuration = (abs(pGun->getRotation() - angleDegrees)
				/ rotateVelocity);
		CCLog("rotateDuration: %f , angleDegrees: %f \n", rotateDuration,
				angleDegrees);

		this->running = true;
		pGun->runAction(
				CCSequence::create(
						CCRotateTo::create(rotateDuration, angleDegrees),
						CCCallFuncN::create(this,
								callfuncN_selector(Game::fire)), NULL));
	}
	return;
}

void Game::menuBackCallback(CCObject* pSender) {
	CCScene *pMenuScene = Menu::scene();
	CCDirector::sharedDirector()->replaceScene(
			CCTransitionFade::create(1, pMenuScene, ccBLACK));
}

void Game::spriteMoveFinished(CCNode *sender) {
	CCSprite *sprite = (CCSprite *) sender;
	this->removeChild(sprite, true);
	pProjectiles->removeObject(sprite, true);
}

void Game::fire(CCNode *sender) {
	// Bail out if we are shooting down or backwards
	CCSprite *projectile = CCSprite::create("projectile.png");
	projectile->setTag(projectileTag);
	this->pProjectiles->addObject(projectile);
	projectile->setPosition(
			ccp(this->gunPosition.x +
					sinf(this->angleRadians) * (this->pGun->getContentSize().height + 20) / 2,
					this->gunPosition.y +
					cosf(this->angleRadians) * (this->pGun->getContentSize().height + 20) / 2));

	this->addChild(projectile, 1);
	CocosDenshion::SimpleAudioEngine::sharedEngine()->playEffect("fire.wav");
	CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();
	int realY = visibleSize.height + (projectile->getContentSize().height / 2);
	float ratio = (float) offX / (float) offY;
	int realX = ratio * realY + gunPosition.x;
	CCPoint realDest = ccp(realX, realY);

	int offRealX = realX - gunPosition.x;
	int offRealY = realY - gunPosition.y;

	float length = sqrtf((offRealX * offRealX) + (offRealY * offRealY));

	float velocity = 480 / 1;
	float realMoveDuration = length / velocity;

	projectile->runAction(
			CCSequence::create(CCMoveTo::create(realMoveDuration, realDest),
					CCCallFuncN::create(this,
							callfuncN_selector(Game::spriteMoveFinished)),
					NULL));
	this->running = false;
}
